<template>
  <div class="chat-model-wp">
  	<div ref="msgListRef" class="list" :style="{opacity: _d.msgOpacity}">
			<div v-if="!_d.sessionList.length || !_d.msgList.length" class="no-session-tip">
				<div class="r1">
					<question-circle-filled class="icon" />
					<span>如何开始</span>
				</div>
				<div class="bg mb-10">直接在下方输入问题或内容</div>
				<div class="mb-10">或</div>
				<div class="bg">
					<div class="flex flex-col items-center justify-center">
						<div>
							<span>点击页面左上角</span>
  						<img class="add-img" src="@/assets/image/1.jpg"/>
						</div>
  					<span>创建一个会话主题，然后在下方输入聊天内容</span>
					</div>
				</div>
				<div class="r2">有意思的问题</div>
				<div class="question-list">
					<div v-for="(item, index) in _d.questionList" :key="index" class="item bg"
						@click="sendQuestion(item)">{{item}}</div>
				</div>
			</div>
			<template v-for="(item, index) in _d.msgList">
				<div class="item me">
					<div class="ct">
						<div class="head">
							<template v-if="userStore.userinfo.name">
								{{userStore.userinfo.name.length > 2 ? userStore.userinfo.name.slice(userStore.userinfo.name.length - 2) : userStore.userinfo.name}}
							</template>
						</div>
						<div class="msg">
							<p v-for="(bItem,index) in item.content" :key="index">{{bItem}}</p>
						</div>
					</div>
				</div>
				<div class="item">
					<div class="ct">
						<div class="head"></div>
						<div class="msg">
							<div v-if="_d.gptThinking && index == _d.msgList.length - 1" class="thinkingIcon"></div>
							<template v-for="(bItem, bIndex) in item.respon">
								<p v-if="bItem.type == 'p'">{{ bItem.data }}</p>
								<div v-if="bItem.type == 'code'" class="code-box">
									<div class="code-top">
										<span class="type">{{ bItem.language }}</span>
										<span class="copy-btn" @click="copyText(bItem.data)">Copy code</span>
									</div>
									<highlightjs class="t-high" :language="bItem.language" autodetect :code="bItem.data" />
								</div>
								<div v-if="bItem.type == 'image'" class="image-box">
									<div class="img-list">
										<mImgShow class="img" v-for="(cItem, cIndex) in bItem.data" :key="cIndex" :src="cItem" @click="showImage(cItem)"/>
									</div>
									<div class="img-tip">图片生成相对于文字会更慢，请耐心等待，如果图片很喜欢记得保存。</div>
								</div>
							</template>
							<a-button v-if="item.fileurl" class="down-btn" type="link" @click="downFile(item.fileurl)">下载思维导图文件</a-button>
						</div>
					</div>
				</div>
			</template>
		</div>
		<div class="bottom">
			<div v-if="!_d.isMobil" class="audio-list">
				<div v-for="(item, index) in _d.audioList" :key="index" class="item" @click="audioHandleClick(item)">
					<div class="btn">
						<div class="title">{{item.title}}</div>
  					<div class="text">{{item.text}}</div>
					</div>
				</div>
			</div>
			<div class="send-box">
				<div v-if="!_d.gptThinking && !_d.gptPrint" class="ipt-box">
					<!-- <a-input class="ipt" v-model:value="_d.msgText" :bordered="false" placeholder="请输入发送内容" allowClear @keyup.enter="sendChat($event)" /> -->
					<a-textarea class="ipt" v-model:value="_d.msgText" :bordered="false" placeholder="请输入发送内容" allowClear auto-size @keyup.enter="sendChat($event)"/>
					<img src="@/assets/image/send.png" @click="sendChat()"/>
				</div>
				<div v-else class="thinking">
					<span>Ai is thinking...</span>
					<!-- <span class="stop">Stop</span> -->
				</div>
			</div>
		</div>
  </div>
</template>

<script setup>
	import { reactive, ref, onMounted } from 'vue'

	const _d = reactive({
		msgOpacity: 0,

		gptThinking: false,
		gptPrint: false,
		msgText: '',
		msgList: [],

		// 错误提示
		error: {
			visible: true,
			message: '错误提示一大堆'
		},

		// 是否显示提示
		showTip: false,
		// 问题列表
		questionList: [
			"请用C#代码获取当前系统的时间", "写一篇春游的文章", "什么是计算机技术", "AI是什么?", 
			"宇宙的终极意义是什么", "什么是道可道非常道", "西方哲学思想起源来自哪里?", "把“我爱你“翻译为法语"
		],

		// 文章列表
		showArticle: true,
		articleList: [],

		preview: {
			visible: false,
			src: ''
		},

		// 声音操作
		audioList: [
			{title: '音频文件分析', text: '上传音频文件，提取语言内容以文字形式输出', disabled: false, click: () => {
				uploadModalRef.value.open(_d.sessionList[_d.sessionIdx].id);
			}},
			{title: '音频文件生成', text: '根据语速，语调，场景，输入文字生成音频文件', path: '/textTovoice'},
			{title: '发音评估', text: '输入一段文字，根据您的发音评估发音结果（开发中）'},
			{title: '声音识别', text: '识别周围的声音，转成文字输出', path: '/voiceTotext'},
		],

		headers: {

		},
		fileList: [],
	})
	
	onMounted(() => {
	
	})

	// 新建会话
	function showAddChat() {
		addChatModalRef.value.open();
	}

	// 新建默认会话
	async function addDefaultChat() {
		let params = {
			name: '默认',
			userId: userStore.userinfo.userId
		}
		let res = await ApiPost("/Chat/insertesession", params);
		let data = res.data;
		data.type = 1;
		data.ipt = data.name;
		_d.sessionList.unshift(data);
	}

	// 前加会话
	function unshiftSession(data) {
		data.type = 1;
		data.ipt = data.name;
		_d.sessionList.unshift(data);
		choiceSession(0, true);
	}

	// 删除会话
	function deleteSession(id, index) {
		ApiPost(`/Chat/deletesessions/${id}`).then(res => {
			notification.success({
				message: '提示',
				description: '删除成功'
			});

			if(_d.sessionIdx == index) {
				getSessions();
			} else {
				_d.sessionList.splice(index, 1);
			}
		})
	}

	// 选中会话
	function choiceSession(index, isLoad = false) {
		if(_d.sessionIdx == index && !isLoad) {
			return;
		}
		// 手机端关闭弹窗
		setOpen(false);
		_d.sessionIdx = index;
		userStore.setSessionidx(index);
		getHistoryMsg();
	}

	// 获取历史信息
	function getHistoryMsg() {
		let id = _d.sessionList[_d.sessionIdx].id;
		_d.msgList = [];
		_d.msgOpacity = 0;
		ApiGet(`/Chat/getDiacontent/${id}`).then(async res => {
			if(res.data && res.data.length) {
				_d.msgList = res.data.map(item => {
					item.content = processContent(item.content);
					if(item.respon) {
						if(item.fileurl) { // 思维导图
							item.respon = [{type: 'code', data: item.respon}];
						} else {
							item.respon = processData(item.respon);
						}
					} else {
						let imgs = [];
						for(let key in item) {
							if(key.indexOf('imageurl') == 0 && item[key]) {
								imgs.push(item[key]);
							}
						}
						item.respon = [
							{type: 'image', data: imgs}
						];
					}
					return item;
				})
			} else {
				_d.msgList = [];
			}
			console.log(_d.msgList);
			setScrollTop();
			await waitTimeout(120);
			_d.msgOpacity = 1;
		})
	}

	// 发送问题
	function sendQuestion(text) {
		_d.msgText = text;
		sendChat();
	}

	// 发送会话内容
	async function sendChat(event) {
		if(event && !(event?.altKey)) {
			return;
		}
		// 新建默认会话
		if(!_d.sessionList.length) {
			await addDefaultChat();
		}
		if(!_d.msgText.length) {
			return;
		}
		
		// 判断是否为图片
		let isImage = false;
		if(_d.msgText.indexOf('image') == 0) {
			isImage = true;
			_d.msgText = _d.msgText.replace('image', '');
		}

		// 判断是否为思维导图
		let isMind = false;
		if(_d.msgText.indexOf('mind') == 0) {
			isMind = true;
			_d.msgText = _d.msgText.replace('mind', '');
		}

		_d.msgList.push({
			content: processContent(_d.msgText),
			respon: []
		})
		setScrollTop();

		let params = {
			sessionId: _d.sessionList[_d.sessionIdx].id,
			chatMessage: _d.msgText
		}
		_d.gptThinking = true;

		// 如果是图片
		if(isImage) {
			ApiPost(`/Chat/Startimage`, params, true).then(async res => {
				if(!res || !res.imageurl.length) {
					return;
				}
				_d.msgList[_d.msgList.length-1].respon = [
					{type: 'image', data: res.imageurl}
				];
				await waitTimeout(50);
				setScrollTop();
			}).catch(err => {
				if(err.data) {
					errorModalRef.value.open(err.data);
				}
			}).finally(() => {
				_d.msgText =  '';
				_d.gptThinking = false;
			})
		} else if (isMind) {
			ApiPost(`/Chat/Startmind`, params, true).then(async res => {
				if(!res || res.result != 200) {
					return;
				}
				let index = _d.msgList.length -1;
				gptShowMsg(index, [{type: 'code', data: res.data}], () => {
					_d.msgList[index].fileurl = res.fileurl;
					setScrollTop();
				})
			}).catch(err => {
				if(err.data) {
					errorModalRef.value.open(err.data);
				}
			}).finally(() => {
				_d.msgText =  '';
				_d.gptThinking = false;
			})
		} else {
			let url = '';
			if(_d.modelType == 'GPT3.5') {
				url = '/Chat/Startconversation';
			} else if (_d.modelType.indexOf('QianFan_') == 0) {
				url = '/Chat/StartQianfanchat';
				params.modelurl = modelSelectRef.value.choice().modelurl;
			}
			ApiPost(url, params, true).then(res => {
				if(!res || !res.data.length) {
					return;
				}
				gptShowMsg(_d.msgList.length-1, processData(res.data));
			}).catch(err => {
				if(err.data) {
					errorModalRef.value.open(err.data);
				}
			}).finally(() => {
				_d.msgText =  '';
				_d.gptThinking = false;
			})
		}
	}

	async function gptShowMsg(index, data, callback) {
		let oMsg = _d.msgList[index];
		for(let i = 0; i < data.length; i++) {
			let item = data[i];
			oMsg.respon.push({
				type: item.type,
				language: item.language,
				data: ''
			})

			_d.gptPrint = true;
			let j = 0;
			while(j < item.data.length) {
				oMsg.respon[oMsg.respon.length-1].data+=item.data.charAt(j);
				j++;
				// 最后一集每3次执行一次
		    if(i >= data.length || j % 3 == 0) {
		    	setScrollTop();
		    }
				await waitTimeout(50);
			}
			_d.gptPrint = false;
		}
		if(callback) {
			callback();
		}
	}

	// 转换content问题内容
	function processContent(content) {
		let arr = content.split('\n');
		return arr.filter(item => item.length);
	}


	// 将gpt数据转换为正常数据
	function processData(input) {
		const codeRegex = /```([\s\S]*?)```/g;
		const splitByCode = input.split(codeRegex);
		const output = [];

		for (let i = 0; i < splitByCode.length; i++) {
			// 如果是偶数索引，我们认为是文本
			if (i % 2 === 0) {
				const paragraphs = splitByCode[i].split('\n').filter(p => p.trim() !== '');
				paragraphs.forEach(paragraph => {
					output.push({
						type: 'p',
						// data: paragraph.replace(/\s/g, '&nbsp;'),
						data: paragraph
					});
				});
			}
			// 如果是奇数索引，我们认为是代码
			else {
				const codeAndLanguage = splitByCode[i].split('\n');
				const language = codeAndLanguage[0].trim();
				const code = codeAndLanguage.slice(1).join('\n').trim();

				output.push({
					type: 'code',
					data: code,
					language: language,
				});
			}
		}
		return output;
	}

	// 设置滚动高度
	function setScrollTop() {
		setTimeout(() => {
			msgListRef.value.scrollTop = msgListRef.value.scrollHeight;
		}, 100);
	}


	// 复制到粘贴板
	function copyText(text) {
		if(navigator.clipboard) {
			// 将文本内容复制到剪贴板中
			navigator.clipboard.writeText(text)
			.then(() => {
				notification.success({
					message: '提示',
					description: '文本已成功复制到剪贴板中'
				});
			})
			.catch(() => {
				notification.error({
					message: '提示',
					description: '无法复制文本到剪贴板中'
				});
			});
		} else {
			// 创建临时文本区域元素
			const tempTextArea = document.createElement("textarea");
			tempTextArea.value = text;
			tempTextArea.setAttribute("readonly", "");
			tempTextArea.style.position = "absolute";
			tempTextArea.style.left = "-9999px";
			document.body.appendChild(tempTextArea);

			// 选中文本内容
			tempTextArea.select();
			tempTextArea.setSelectionRange(0, tempTextArea.value.length);

			// 将文本内容复制到剪贴板中
			document.execCommand("copy");

			// 删除临时文本区域元素
			document.body.removeChild(tempTextArea);
			notification.success({
				message: '提示',
				description: '文本已成功复制到剪贴板中'
			});
		}
	}
	
</script>

<style scoped>
.chat-model-wp {
	height: 0;
	flex: 1;
	display: flex;
	flex-direction: column;

	.list {
		flex: 1;
		height: 0;
		background: #F5F7F9;
		overflow: auto;
		.item {
			padding: 10px 20px;
			border-bottom: 1px solid #EDEDEE;
			.ct {
				position: relative;
				margin: 0 auto;
				max-width: 100%;
				width: 768px;
				padding: 10px 0 10px 54px;
				font-size: 16px;
				line-height: 28px;
				.head {
					position: absolute;
					top: 9px;
					left: 0;
					width: 30px;
					height: 30px;
					background: url(@/assets/image/chat.png) no-repeat center;
					background-size: 100% 100%;
				}
				.msg {
					min-height: 28px;
					word-break: break-word;
					.thinkingIcon {
						width: 5px;
						height: 28px;
						border-top: 6px solid transparent;
						border-bottom: 6px solid transparent;
						background: #000;
						background-clip: content-box;
						animation: thinkingAnim .7s infinite;
					}
				}
				p {
					margin-bottom: 10px;
				}
				P:last-child{
					margin-bottom: 0;
				}
				.code-box {
					font-size: 12px;
					line-height: 24px;
					min-height: 80px;
					.code-top {
						padding: 15px;
						background: #353641;
						height: 32px;
						display: flex;
						align-items: center;
						justify-content: space-between;
						color: #fff;
						cursor: pointer;
						font-size: 14px;
						.copy-btn {
							padding-left : 25px;
							background: url(@/assets/image/copy.png) no-repeat left center;
							background-size: 20px auto;
							font-size: 14px;
						}
					}
				}
				.image-box {
					.img-list {
						&:after {
							content: '';
							display: block;
							clear: both;
						}
						.img {
							float: left;
							margin-right: 20px;
							width: 200px;
							height: 200px;
							cursor: pointer;
						}
					}
					.img-tip {
						margin-top: 5px;
						color: #aaa;
						font-size: 12px;
					}
				}
			}
			&.me {
				background: #fff;
				.head {
					background: #9951AB;
					color: #fff;
					text-align: center;
					font-size: 14px;
					line-height: 30px;
				}
			}
		}
	}
	.bottom {
		padding: 20px 20px;
		background: #fff;
		border-top: 1px solid #F2EFF4;
		.audio-list {
			display: flex;
			gap: 15px;
			margin: 0 auto;
			max-width: 100%;
			width: 768px;
			margin-bottom: 10px;
			.item {
				flex: 1;
				.btn {
					height: 70px;
					color: #fff;
					background: #138496;
					padding: 0 10px;
					border-radius: 4px;
					cursor: pointer;
					.title {
						padding: 3px 0 2px;
						font-size: 14px;
						text-align: center;
					}
					.text {
						font-size: 12px;
						line-height: 18px;
					}
				}
			}
		}
		.send-box {
			margin: 0 auto;
			max-width: 100%;
			width: 768px;
			border: 1px solid #E1E2E6;
			box-shadow: 0 0 10px rgba(0,0,0,.1);
			border-radius: 2px;
			display: flex;
			align-items: center;
			.ipt-box {
				position: relative;
				width: 100%;
				padding: 10px 35px 10px 20px;
				.ipt {
					width: 100%;
				}
				img {
					position: absolute;
					top: 50%;
					z-index: 2;
					margin-top: -10px;
					right: 15px;
					width: 20px;
					height: 20px;
					cursor: pointer;
				}
			}
			.thinking {
				width: 100%;
				height: 100%;
				min-height: 52px;
				display: flex;
				align-items: center;
				justify-content: center;
				.stop {
					margin-left: 10px;
					padding: 2px 10px;
					border: 1px solid #ccc;
					border-radius: 8px;
					cursor: pointer;
				}
			}
		}
	}
}

@media screen and (max-width: 900px) {
	.list {
		.item {
			padding: 5px 10px;
			.ct {
				padding-left: 40px;
				font-size: 14px;
				line-height: 22px;
				.head {
					top: 6px;
				}
				.msg {
					min-height: 22px;
					p:not(:last-child) {
						margin-bottom: 5px;
					}
				}
			}
		}
	}
	.bottom {
		padding: 10px 20px;
		.audio-list {
			flex-wrap: wrap;
			justify-content: space-between;
			.item {
				flex: none;
				width: 47%;
				gap: 0;
				.btn {
					
				}
			}
		}
		.send-box {
			.ipt-box {
				padding: 0 10px 0 0;
				gap: 0;
			}
		}
	}
}
</style>